 /*******************************************************************************
  * Copyright (c) 2000, 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal.editors.quickdiff;

 import java.util.ResourceBundle ;

 import org.eclipse.jface.viewers.IPostSelectionProvider;
 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionChangedListener;
 import org.eclipse.jface.viewers.ISelectionProvider;
 import org.eclipse.jface.viewers.SelectionChangedEvent;

 import org.eclipse.jface.text.IRewriteTarget;
 import org.eclipse.jface.text.ITextSelection;
 import org.eclipse.jface.text.source.IAnnotationModel;
 import org.eclipse.jface.text.source.IAnnotationModelExtension;
 import org.eclipse.jface.text.source.IChangeRulerColumn;
 import org.eclipse.jface.text.source.ILineDiffer;
 import org.eclipse.jface.text.source.IVerticalRulerInfo;

 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.texteditor.IDocumentProvider;
 import org.eclipse.ui.texteditor.IEditorStatusLine;
 import org.eclipse.ui.texteditor.ITextEditor;
 import org.eclipse.ui.texteditor.TextEditorAction;

 /**
  * Abstract superclass of actions that restore / revert parts of a document displayed in the action's
  * editor to the state described by the {@link ILineDiffer ILineDiffer} associated with the document's
  * {@link IAnnotationModel IAnnotationModel}.
  *
  * @since 3.1
  */
 public abstract class QuickDiffRestoreAction extends TextEditorAction implements ISelectionChangedListener {

     private int fLastLine= -1;
     private final boolean fIsRulerAction;

     /**
      * Creates a new instance.
      *
      * @param bundle the resource bundle
      * @param prefix a prefix to be prepended to the various resource keys
      * @param editor the editor this action belongs to
      * @param isRulerAction <code>true</code> if this is a ruler action
      */
     QuickDiffRestoreAction(ResourceBundle bundle, String prefix, ITextEditor editor, boolean isRulerAction) {
         super(bundle, prefix, editor);
         fIsRulerAction= isRulerAction;

         ISelectionProvider selectionProvider= editor.getSelectionProvider();
         if (selectionProvider instanceof IPostSelectionProvider)
             ((IPostSelectionProvider)selectionProvider).addPostSelectionChangedListener(this);
     }

     /**
      * Called by this action's run method inside a pair of calls to <code>IRewriteTarget.beginCompoundChange</code>
      * and <code>IRewriteTarget.endCompoundChange</code>().
      *
      * @see IRewriteTarget
      */
     protected abstract void runCompoundChange();

     /*
      * @see org.eclipse.jface.action.IAction#run()
      */
     public void run() {
         ITextEditor editor= getTextEditor();
         if (editor == null || !validateEditorInputState())
             return;
         IRewriteTarget target= (IRewriteTarget)editor.getAdapter(IRewriteTarget.class);
         if (target != null)
             target.beginCompoundChange();
         runCompoundChange();
         if (target != null)
             target.endCompoundChange();

     }

     /*
      * @see org.eclipse.ui.texteditor.IUpdate#update()
      */
     public void update() {
         /*
          * Update only works if we're updated from the ruler action
          * (see AbstractDecoratedTextEditor.rulerContextMenuAboutToShow).
          */
         super.update();

         setEnabled(computeEnablement());
     }
     
     /*
      * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
      * @since 3.3
      */
     public void selectionChanged(SelectionChangedEvent event) {
         update();
     }

     /**
      * Computes, caches and returns the internal state, including enablement.
      *
      * @return <code>true</code> if the action is enabled, <code>false</code>
      * if it is not
      */
     protected boolean computeEnablement() {
         if (!super.isEnabled())
             return false;

         if (!canModifyEditor())
             return false;

         fLastLine= computeLine(fIsRulerAction);
         return true;
     }

     /**
      * Returns the selection of the editor this action belongs to.
      *
      * @return the editor's selection, or <code>null</code>
      */
     protected ITextSelection getSelection() {
         if (getTextEditor() == null)
             return null;
         ISelectionProvider sp= getTextEditor().getSelectionProvider();
         if (sp == null)
             return null;
         ISelection s= sp.getSelection();
         if (s instanceof ITextSelection)
             return (ITextSelection)s;
         return null;
     }

     /**
      * Returns the current line of activity
      *
      * @return the currently active line
      * @since 3.1
      */
     protected int getLastLine() {
         return fLastLine;
     }

     /**
      * Returns the active line
      *
      * @param useRulerInfo
      * @return the line of interest.
      * @since 3.1
      */
     private int computeLine(boolean useRulerInfo) {
         int lastLine;
         if (useRulerInfo) {
             IVerticalRulerInfo ruler= getRuler();
             if (ruler == null)
                 lastLine= -1;
             else
                 lastLine= ruler.getLineOfLastMouseButtonActivity();
         } else {
             ITextSelection selection= getSelection();
             if (selection == null)
                 lastLine= -1;
             else
                 lastLine= selection.getEndLine();
         }
         return lastLine;
     }

     /**
      * Returns the annotation model of the document displayed in this action's editor, if it
      * implements the {@link IAnnotationModelExtension IAnnotationModelExtension} interface.
      *
      * @return the displayed document's annotation model if it is an <code>IAnnotationModelExtension</code>, or <code>null</code>
      */
     private IAnnotationModelExtension getModel() {
         if (getTextEditor() == null)
             return null;
         IDocumentProvider provider= getTextEditor().getDocumentProvider();
         IEditorInput editorInput= getTextEditor().getEditorInput();
         IAnnotationModel m= provider.getAnnotationModel(editorInput);
         if (m instanceof IAnnotationModelExtension)
             return (IAnnotationModelExtension)m;
         return null;
     }

     /**
      * Returns the diff model associated with the annotation model of the document currently displayed
      * in this action's editor, if any.
      *
      * @return the diff model associated with the displayed document, or <code>null</code>
      */
     protected ILineDiffer getDiffer() {
         IAnnotationModelExtension extension= getModel();
         if (extension != null)
             return (ILineDiffer)extension.getAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID);
         return null;
     }

     /**
      * Returns a <code>IVerticalRulerInfo</code> if this action's editor adapts to one.
      *
      * @return the <code>IVerticalRulerInfo</code> for the editor's vertical ruler, or <code>null</code>
      */
     protected IVerticalRulerInfo getRuler() {
         if (getTextEditor() != null)
             return (IVerticalRulerInfo)getTextEditor().getAdapter(IVerticalRulerInfo.class);
         return null;
     }

     /**
      * Sets the status line error message to <code>string</code>.
      *
      * @param string the message to be displayed as error.
      */
     protected void setStatus(String string) {
         if (getTextEditor() != null) {
             IEditorStatusLine statusLine= (IEditorStatusLine) getTextEditor().getAdapter(IEditorStatusLine.class);
             if (statusLine != null) {
                 statusLine.setMessage(true, string, null);
             }
         }
     }
 }

